/*
 * lockstest.c
 *
 *  Created on: Jun 12, 2011
 *      Author: peckb1
 */

#ifndef LOCKSTEST_C_
#define LOCKSTEST_C_


#include "syscall.h"

#include <usercommon.h>

int lockId;
int CVid;

static int sharedDataOne = -1;
static int sharedDataTwo = -1;

static int testLocksLock;
static int testLocksMV;

void firstLockTest() {

    /* Tests signaling on a lock with no one waiting */
    printf("\nTesting Signal on a lock no one owns\n\t");

    lockId = CreateLock("Signal w/ no one waiting Lock");
    CVid = CreateCV("Signal w/ no one waiting Condition");

    Signal(CVid, lockId);

    DestroyCV(CVid);
    DestroyLock(lockId);
}

void secondLockHelperThreadOne() {

    Acquire(testLocksLock);


    /* Waits on a Lock to be awoken by someone else */
    printf("\tThread will wait to be woken up\n\t");

    sharedDataOne = CreateLock("Waiting Lock");

    testLocksMV ++;


    Acquire(sharedDataOne);

    sharedDataTwo = CreateCV("Waiting CV");

    testLocksMV ++;


    Release(testLocksLock);


    printf_5("Waiting on CV: ", sharedDataTwo, " - Lock: ", sharedDataOne , "\n");

    Wait(sharedDataTwo, sharedDataOne);

    printf("\tWoken from waiting\n");

    Release(sharedDataOne);

    DestroyCV(sharedDataTwo);
    DestroyLock(sharedDataOne);

    DestroyLock(testLocksLock);
    sharedDataOne = -2;
    sharedDataTwo = -2;

    Exit(0);
}

void secondLockHelperThreadTwo() {

    /* Will wake up the sleeping secondLockHelperThreadOne thread */
    Acquire(testLocksLock);
    while(testLocksMV < 2) {
        Release(testLocksLock);

        Yield();/* busy loop because we don't have semaphores T.T */
        Acquire(testLocksLock);

    }

    testLocksMV = 0;
    Release(testLocksLock);

    Acquire(sharedDataOne);

    printf("\tBroadcasting to a CV\n");

    Broadcast(sharedDataTwo, sharedDataOne);
    Release(sharedDataOne);

    Exit(0);
}

void
secondLockTest() {
    testLocksLock = CreateLock("Test Lock Lock");
    /* Tests waiting on a lock */
    Fork("Lock Helper Thread Test One", 27, secondLockHelperThreadOne);
    Fork("Lock Helper Thread Test Two", 27, secondLockHelperThreadTwo);


}

int lock;

void
thirdLockTest() {
    /* Will release a lock it doesn't own */
    printf("Releasing a lock I don't own\n\t");
    lock = CreateLock("Lock to release that I don't own");
    Release(lock);
    DestroyLock(lock);
}


void
fourthLockTest() {
    /* Makes sure that Create Lock gives us a lock we can do all the lock methods upon */
    lockId = CreateLock("Test a bunch of things Lock");
    CVid = CreateCV("Test a bunch of things CV");

    printf_3("Called create lock, received the following lock Id: ", lockId, ".\n");

    printf_3("Acquiring Lock (", lockId, ") no error should occur.\n");
    Acquire(lockId);

    printf_3("\nReleasing Lock (", lockId, ") no error should occur.\n");
    Release(lockId);

    printf_3("\nSignaling on a lock (", lockId, ") I just created, an error should appear.\n");
    Signal(CVid, lockId);

    printf_3("\nBroadcasting on a lock (", lockId, ") with no one waiting - no error as our implementation of broadcast checks if the list is empty before broadcasting.\n");
    Broadcast(CVid, lockId);

    printf_3("\nDestroying the lock (", lockId, ") I received before, no error should occur.\n");
    DestroyLock(lockId);

    printf_3("\nCalling acquire on deleted lock (", lockId, "), should get an error.\n");
    Acquire(lockId);

    printf_3("\nCalling Release on a deleted lock (", lockId, "), should get an error.\n");
    Release(lockId);

    printf_3("\nCalling Signal on a deleted lock (", lockId, "), should get an error.\n");
    Signal(CVid, lockId);
}

void fifthLockHelperThreadOne() {
    sharedDataOne = CreateLock("Lock to wait on, then delete, then be signaled");
    sharedDataTwo = CreateCV("CV to help fifthLockHelper Test");

    Acquire(sharedDataOne);

    Acquire(testLocksLock);
    testLocksMV ++;
    Release(testLocksLock);

    printf("Waiting on lock that will be deleted before I wake up.\n");
    Wait(sharedDataTwo, sharedDataOne);

    printf("Was awoken on a lock/cv that had been deleted.\n");

    printf("\nWill now try and do things to a lock/cv that is now deleted\n");
    printf("First a release, which should be ok, since we own the lock\n");
    Release(sharedDataOne);

    printf("\nNow errors should occur \n");
    printf("\n ERROR: ");
    Acquire(sharedDataOne);

    printf("\n ERROR: ");
    Wait(sharedDataTwo, sharedDataOne);
    printf("\n ERROR: ");
    Signal(sharedDataTwo, sharedDataOne);
    printf("\n ERROR: ");
    Broadcast(sharedDataTwo, sharedDataOne);
    printf("\n ERROR: ");
    DestroyLock(sharedDataOne);
    printf("\n ERROR: ");
    DestroyCV(sharedDataTwo);



    testLocksMV = 0;
    DestroyLock(testLocksLock);

    sharedDataTwo = -3;
    sharedDataTwo = -3;
    Exit(0);
}

void fifthLockHelperThreadTwo() {
    Acquire(testLocksLock);
    while(testLocksMV < 1) {
        Release(testLocksLock);
        Yield();/* busy loop because we don't have semaphores T.T */
        Acquire(testLocksLock);
    }

    printf("Deleting the lock/cv that 5th test is waiting for.\n");
    /* Deleting the lock and CV */
    DestroyLock(sharedDataOne);
    DestroyCV(sharedDataTwo);

    printf("\nNow trying to make calls onto a lock/cv that has been deleted\n");

    printf("\n ERROR: ");
    Acquire(sharedDataOne);
    printf("\n ERROR: ");
    Release(sharedDataOne);
    printf("\n ERROR: ");
    Wait(sharedDataTwo, sharedDataOne);
    printf("\n ERROR: ");
    DestroyLock(sharedDataOne);
    printf("\n ERROR: ");
    DestroyCV(sharedDataTwo);


    printf("\nSignaling on the lock/cv that are deleted, but someone is still waiting.\n");
    Signal(sharedDataTwo, sharedDataOne);

    Exit(0);
}

void fifthLockTest() {
    testLocksLock = CreateLock("Test Lock Lock");
    /* Makes sure that even if a lock is deleted, if there is someone waiting on the Lock they can be released */
    Fork("Test 5 Helper Thread one", 24, fifthLockHelperThreadOne);
    Fork("Test 5 Helper Thread one", 24, fifthLockHelperThreadTwo);


}

int tmp;
int first;
int i;

void sixthLockTest() {

    printf("Lets make a lot of locks.\n");

    first = CreateLock("First Lock");

    while(tmp < 300000) {
        tmp = CreateLock("I'm a lock\n");
        if(tmp % 10000 == 0) {
            printf_3("Made 10000 locks, lock# = ", tmp, "\n");
        }
    }

    printf("Deleting locks we just made.\n");
    for(i = first; i <= tmp; i++) {
        DestroyLock(i);
        if(i % 10000 == 0) {
            printf_3("Destroyed 10000 locks, lock just deleted = ", i, "\n");
        }
    }
}

void seventhLockTest() {
    printf("\nTesting deleting locks that should not exist.\n");

    printf("\nTesting -1\n");
    DestroyLock(-1);

    printf("\nTesting 10\n");
    DestroyLock(10);

    printf("\nTesting 11\n");
    DestroyLock(11);

    printf("\nTesting deleting CVs that should not exist.\n");

    printf("\nTesting -1\n");
    DestroyCV(-1);

    printf("\nTesting 0\n");
    DestroyCV(0);

    printf("\nTesting 1\n");
    DestroyCV(1);

}

int i;
int newCV;

int
main() {
    printLock = CreateLock("Printing Lock");

    printf("\n\n");
    printf("---------- Test #7\\n\n\n\n");
    seventhLockTest();

    printf("\n\n");
    printf("---------- Test #1\n");

    firstLockTest();

    printf("\n\n");
    printf("---------- Test #2\n");
    secondLockTest();

    while(sharedDataOne != -2 && sharedDataTwo != -2) {
        Yield();
    }

    printf("\n\n");
    printf("---------- Test #3\n");
    thirdLockTest();

    printf("\n\n");
    printf("---------- Test #4\n");
    fourthLockTest();

    printf("\n\n");
    printf("---------- Test #5\n");
    fifthLockTest();

    while(sharedDataOne != -3 && sharedDataTwo != -3) {
        Yield();
    }

    printf("\n\n");
    printf("---------- Test #6\n");
    sixthLockTest();

    printf("\nStopping lock / cv testing\n\n");
    Exit(0);
}

#endif
